﻿using System;
using System.Collections.Generic;
using System.Collections;
using Layers;

namespace HoldemGame
{

    public static class Suits
    {
        public static int Clubs       = 0;
        public static int Diamonds    = 1;
        public static int Hearts      = 2;
        public static int Spades      = 3;
    }

    public static class Ranks
    {
        public static int Two = 2;
        public static int Three=3;
        public static int Four=4;
        public static int Five=5;
        public static int Six=6;
        public static int Seven=7;
        public static int Eight=8;
        public static int Nine=9;
        public static int Ten=10;
        public static int Jack=11;
        public static int Queen=12;
        public static int King=13;
        public static int Ace=14;
    }

    /// <summary>
    /// One single card.
    /// 
    /// Card is represented by the code, which is bit array
    /// ssss rrrr, 
    /// here:
    ///  ssss - 4 bit for card suit (0..3)
    ///  rrrr - 4 bit for card rank (2..14)
    /// </summary>
    
    public struct Card:IComparable<Card>,IEquatable<Card>
    {
        #region Fields
        internal int _value;
        #endregion

        #region Card Naming
        private static string[] _rankChar = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A","?","?" };
        private static string[] _rankName = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace","?","?" };
         private static string[] _suiteChar = new string[] { "c", "d", "h", "s" };
        #endregion

        #region Properties
        
        public int Value { get { return _value; } set { _value = value; } }

        public int Suit { get { return SuitFromValue(_value);  } }

        
        public bool IsBlack(){
            return Suit == Suits.Clubs || Suit == Suits.Spades;
        }

        public int Rank { get {return RankFromValue(_value); } }

        public static int RankFromValue(int value)
        {
            return (value & 0xF);
        }

        public static int SuitFromValue(int value)
        {
            return (value >> 4);
        }

        public static ulong MaskFromValue(int value)
        {
            return 1ul<<value;
        }
        public ulong MaskValue { get { return MaskFromValue(_value); } }

        #endregion

        #region Constructors
        public Card(int code) { _value = code; }

        public Card(int suit, int rank) : this(ValueFromSuitRank(suit,rank)){}

        public static int ValueFromSuitRank(int suit, int rank)
        {
            return (suit << 4) | rank;
        }

        public static Card FromValue(int value) 
        {
            return new Card(value); 
        }

        public static bool IsValidValue(int value)
        {
            int suit = SuitFromValue(value);
            int rank = RankFromValue(value);

            if (suit >= 0 && suit <= 3
                 && rank >= (int)Ranks.Two && rank <= (int)Ranks.Ace)
                return true;
            return false;
        }

        public static void SkipSpace(string input, ref int pos)
        {
            while (pos < input.Length && " \t\n\r".IndexOf(input[pos]) >= 0)
                pos++;
        }
        /// <summary>
        /// Parses card
        /// samples: As, Qc
        /// </summary>
        /// <param name="input"></param>
        /// <param name="pos"></param>
        /// <returns></returns>
        /// 
        public static Card Parse(string input, ref int pos)
        {
            string tok;

            SkipSpace(input, ref pos);

            if (pos + 2 > input.Length)
                return Card.Invalid;

            if (input.Substring(pos, 2).Equals("??"))
            {
               // pos += 2;
               // return Card.Invalid;
            }

            tok = input.Substring(pos,1);
            int rank = Card.ParseRank(tok);
            if (rank < 0)
                return Card.Invalid;
            pos++;

            tok = input.Substring(pos, 1);
            int suit = Card.ParseSuit(tok);
            if (rank < 0)
                return Card.Invalid;
            pos++;

            return FromSuitRank(suit, rank);
        }

        public static Card Parse(string input)
        {
            int pos = 0;
            return Parse(input, ref pos);
        }

        public static Card Min = Card.FromSuitRank(0, Ranks.Two);
        public static Card Max = Card.FromSuitRank(3, Ranks.Ace);

        public static Card Invalid = Card.FromValue(-1);
        public static Card Empty = Card.FromValue(0);

        public static bool operator==(Card left, Card right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(Card left, Card right)
        {
            return !left.Equals(right);
        }

        public bool IsValid { get { return IsValidValue(Value); } }

        internal static int ParseRank(string rank)
        {
            for (int i = 0; i < _rankChar.Length; i++)
                if (rank.Equals(_rankChar[i]))
                    return i;
            return -1;
        }

        internal static int ParseSuit(string suit)
        {
            for (int i = 0; i < _suiteChar.Length; i++)
                if (suit.Equals(_suiteChar[i]))
                    return i;
            return -1;
        }

        public static string RankChar(int rank)
        {
            return _rankChar[rank];
        }

        public static string SuitChar(int suit)
        {
            return _suiteChar[suit];
        }

        public static Card FromSuitRank(int suit, int rank) { return new Card(suit, rank); }
        #endregion
        
        #region Hash, Debug
        public override string ToString()
        {
            if (!IsValidValue(_value))
                return "??";
            return _rankChar[Rank] + _suiteChar[Suit];
        }

        public override int GetHashCode()
        {
            return _value;
        }
        #endregion

        #region IComparable<Card> Members


        /// <summary>
        /// Orders cards so that higher Rank are first. 
        /// With equal ranks cards are ordered by suits.
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int CompareTo(Card other)
        {
            int r = other.Rank - Rank;
            if (r != 0)
                return r;
            return other.Suit - Suit;
        }

        #endregion
    
        #region IEquatable<Card> Members

        public bool  Equals(Card other)
        {
 	        return this.Value==other.Value;
        }

        #endregion
    }
}